#pragma once

#include<iostream>
#include<string>
#include<sstream>
#include<unistd.h>
#include<sys/stat.h>
#include<string>
#include<vector>
#include<unordered_map>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/sendfile.h>
#include<fcntl.h>
#include<algorithm>
#include"Util.hpp"
#include"log.hpp"

#define SEP ": " //分隔符利用宏定义
#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define LINE_END "\r\n" //行分隔符

#define OK 200
#define NOT_FOUND 404

//状态码和状态码描述
// class Code2Desc
// {
// private:
//     std::unordered_map<int,std::string> code2desc;

// public:
//     Code2Desc(){}
//     void InitCode2Desc()
//     {

//     }
//     ~Code2Desc(){}

// };
static std::string Code2Desc(int code)
{
    std::string desc;
    switch(code)
    {
        case 200:
            desc ="OK";
            break;
        case 404:
            desc = "Not Found";
            break;
        default:
            break;
    }
    return desc;
}

static std::string  Suffix2Desc(const std::string &suffix)
{
    static std::unordered_map<std::string,std::string> suffix2desc = 
    {
        {".html","text/html"},
        {".css" , "text/css"},
        {".js" , "application/javascript"},
        {".jpg","application/x-jpg"},
        {".xml","application/xml"},
    };

    auto iter = suffix2desc.find(suffix);
    if(iter != suffix2desc.end())
    {
        //找到了目标后缀
        return iter->second;
    }
    //没找到则使用默认值
    return "text/html";
}

class HttpRequest
{
public:
    std::string request_line;//请求行
    std::vector<std::string> request_header;
    std::string blank;
    std::string request_body;

    //解析后的结果(方法、URL、版本)
    std::string method;
    std::string url;
    std::string version;

    //解析后结果放入kv中
    std::unordered_map<std::string , std::string> header_kv;
    int content_length;
    std::string suffix;//后缀
    std::string path;//访问的资源路径
    std::string query_string;

    bool cgi;//cgi标志位
    int size;
public:
    HttpRequest():content_length(0),cgi(false){}
    ~HttpRequest(){}
};

class HttpResponse
{
public:
    std::string status_line;
    std::vector<std::string>response_header;
    std::string blank;
    std::string response_body;

    int status_code;//状态码
    int fd;
    int size;//正文资源的大小
    
public:
    HttpResponse():blank(LINE_END),status_code(OK),fd(-1){}
    ~HttpResponse(){}
};

//读取请求、分析请求、构建响应、IO通信
class EndPoint
{
private:
    int sock;
    HttpRequest http_request;
    HttpResponse http_response;
private:
    void RecvHttpRequestLine()
    {
        auto &line = http_request.request_line;
        //读取首行到http_request的首行中去
        Util::ReadLine(sock,line);
        line.resize(line.size()-1);
        LOG(INFO,http_request.request_line);
    }

    void RecvHttpRequestHeader()
    {
        std::string line;
        while(true)
        {
            //每次读取前保证缓冲Line是空的
            line.clear();
            Util::ReadLine(sock,line);
            if(line == "\n") break;
            line.resize(line.size()-1);
            http_request.request_header.push_back(line);
            LOG(INFO,line);
        }
        if(line == "\n")
        {
            http_request.blank = line;
        }
    }

    void ParseHttpRequestLine()
    {
        auto & line = http_request.request_line; 
        std::stringstream ss(line);
        ss>>http_request.method>>http_request.url>>http_request.version;
        //将请求全部转化为大写
        auto&method = http_request.method;
        std::transform(method.begin(),method.end(),method.begin(),::toupper);

        // LOG(INFO,"--------------验证解析后结果是否正确");
        // LOG(INFO,http_request.method);
        // LOG(INFO,http_request.url);
        // LOG(INFO,http_request.version);
    }

    void  ParseHttpRequestHeader()
    {
        for(auto & iter:http_request.request_header)
        {
            std::string key;
            std::string value;
            if(Util::CutString(iter,key,value,SEP))
            {
                http_request.header_kv.insert({key,value});
            }

            // std::cout<<"debug:"<<key<<std::endl;
            // std::cout<<"debug:"<<value<<std::endl;
        }
    }

    bool  IsNeedRecvHttpRequestBody()
    {
        auto &method = http_request.method;
        if(method == "POST")
        {
            auto &header_kv = http_request.header_kv;
            auto iter = header_kv.find("Content-Length");
            if(iter != header_kv.end())
            {
                //转换成整数存储到content_length中
                http_request.content_length = atoi(iter->second.c_str());
                //确认使用POST方法，并且报文有相应长度的时候，下面便可以开始报文的读取
                return true;
            }
        }
        return false;
    }

    void RecvHttpRequestBody()
    {
        if(IsNeedRecvHttpRequestBody())
        {
            int content_length = http_request.content_length;//读取内容的长度
            auto &body = http_request.request_body;//内容

            char ch =0;
            while (content_length)
            {
                ssize_t s = recv(sock,&ch,1,0);
                if(s>0)
                {
                    body.push_back(ch);
                    content_length--;
                }
                else 
                {
                    break;
                }
            }
            
        }
    }

    int  ProcessNonCgi(int size)
    {
        http_response.fd = open(http_request.path.c_str(),O_RDONLY);
        //只有打开文件成功，才构建以下属性
        if(http_response.fd >= 0)
        {
            //状态行
            http_response.status_line = HTTP_VERSION;
            http_response.status_line +=" ";
            http_response.status_line += std::to_string(http_response.status_code);
            http_response.status_line +=" ";
            http_response.status_line += Code2Desc(http_response.status_code);
            http_response.status_line += LINE_END;
            http_response.fd = open(http_request.path.c_str(),O_RDONLY);
            http_response.size = size;

            std::string header_line = "Content-Length: ";
            header_line += std::to_string(size);
            header_line += LINE_END;
            http_response.response_header.push_back(header_line);

            header_line += "Content-Type: ";
            header_line += Suffix2Desc(http_request.suffix); 
            header_line += LINE_END;
            http_response.response_header.push_back(header_line);

            return OK;
        }
       
        return 404;
    }

    int ProcessCgi()
    {
        std::cout<<"debug:"<<"Use cgi model process"<<std::endl;

        return OK;
    }

public:
    EndPoint(int _sock):sock(_sock)
    {}
    //读取请求
    void RcvHttpRequest()
    {
        RecvHttpRequestLine();
        RecvHttpRequestHeader();
        ParseHttpRequestLine();
        ParseHttpRequestHeader();
        RecvHttpRequestBody();
    }
    //解析请求 
    void ParseHttpRequest()
    {
        ParseHttpRequestLine();
        //解析报头
        ParseHttpRequestHeader();
        //读取正文
        RecvHttpRequestBody();
    }
    //构建响应
    void BuildHttpResponse()
    {
        std::string _path;
        int size=0;
        struct stat st;//获取文件属性的结构体
        std::size_t found = 0;
        auto&code = http_response.status_code;
        if(http_request.method !="GET" && http_request.method!="POST")
        {
            //非法请求处理
            LOG(WARNING,"http method is not found");
            code = NOT_FOUND;
            goto END;
        }
        //GET方法下确认请求报文是否带参，然后进行相应的处理
        if(http_request.method == "GET")
        {  
            size_t pos = http_request.url.find('?');
            if(pos!=std::string::npos)
            {
                Util::CutString(http_request.url ,http_request.path,http_request.query_string,"?");
                //get方法带参处理同样使用cgi
                http_request.cgi = true;
            }
            else
            {
              //不带参数情况,路径就是初始只
              http_request.path = http_request.url;
            }
        }
        else if(http_request.method=="POST")
        {
            //POST方法处理
            http_request.cgi = true;
        }
        else
        {

        }
        //给请求加上自己的根目录
        _path = http_request.path;
        http_request.path = WEB_ROOT;
        http_request.path+=_path;
        //如果没有指定访问资源，则返回首页信息
        if(http_request.path[http_request.path.size()-1]=='/')
        {
            http_request.path+=HOME_PAGE;
        }
        //如果获取请求路径资源成功，则证明资源是存在的，否则资源不存在
        if(stat(http_request.path.c_str(),&st)==0)
        {
            //资源存在
            if(S_ISDIR(st.st_mode))
            {
                //此时访的是一个目录，需要对其进行处理(上述请求的路径中不带/，所以此时需要加上)
                http_request.path +="/";
                http_request.path +=HOME_PAGE;
                //重新获取其属性信息
                stat(http_request.path.c_str(),&st);
            }
            //如果三种文件属性任意一个存在，则表示文件是可执行的
            if((st.st_mode&S_IXUSR)||(st.st_mode&S_IXGRP)||(st.st_mode&S_IXOTH))
            { 
                http_request.cgi = true;
            }
            size = st.st_size;
        }
        else
        {
            std::string info = http_request.path; 
            info +="Not Found!";
            LOG(WARNING,info);
            code = NOT_FOUND;
            goto END;
        }

        //此时文件一定存在path中，提取文件的后缀
        found = http_request.path.rfind(".");
        if(found == std::string::npos)
        {
            //没找到默认将其后缀设置成.html
            http_request.suffix = ".html";
        }
        else 
        {
            http_request.suffix = http_request.path.substr(found);
        }

        if(http_request.cgi)
        {
            //cgi方式处理请求
            code = ProcessCgi();
        }
        else 
        {
            //非cgi方式处理请求，返回静态网页(构建http响应)
           code = ProcessNonCgi(size);
        }
        
        // std::cout<<"debug:"<<http_request.path<<std::endl;
        // std::cout<<"debug:url-"<<http_request.url<<std::endl;
        // std::cout<<"debug:path-"<<http_request.path<<std::endl;
        // std::cout<<"debug:query_string-"<<http_request.query_string<<std::endl;
END:
    if(code !=OK)
    {

    }
    return;
    }
    //发送响应
    void SendHttpResponse() 
    {
        //发送状态行
         send(sock,http_response.status_line.c_str(),http_response.status_line.size(),0);
         for(auto iter : http_response.response_header)
         {
            send(sock,iter.c_str(),iter.size(),0);
         }
         send(sock,http_response.blank.c_str(),http_response.blank.size(),0);

         //正文发送
         sendfile(sock,http_response.fd,nullptr,http_response.size);
         close(http_response.fd);
    }
    ~EndPoint()
    {
        close(sock);
    }
};

// #define DEBUG 1
class Entrance
{
    public:
        static void*HandlerRequest(void *_sock)
        {
            LOG(INFO,"Hander Request begin");
            int sock = *(int*)_sock;
            delete(int*)_sock;
            // std::cout<<"get a new link :"<<sock<<std::endl;

#ifdef DEBUG
            char buffer[4096];
            recv(sock,buffer,sizeof(buffer),0);
            std::cout<<"________________begin"<<std::endl;
            std::cout<<buffer<<std::endl;
             std::cout<<"________________end"<<std::endl;
#else   
            EndPoint*ep = new EndPoint(sock);
            ep->RcvHttpRequest();
            // ep->ParseHttpRequest();
            ep->BuildHttpResponse();
            ep->SendHttpResponse();
            delete ep;
#endif

            // std::string line;
            // Util::ReadLine(sock,line); 
            // std::cout<<line<<std::endl;
            // close(sock);

            LOG(INFO,"Hander Request End");
            return nullptr;
        }
};